#ifndef __STXEXTPROTOCOL_H__
#define __STXEXTPROTOCOL_H__

#include "communication/commdef.h"
#include "lib/stringex.h"

//协议数据最大长度
#define PROTOCOL_DATA_MAX_LEN 128
//cmd [0-15]命令  [16-23]地址
#define PROTOCOL_DEF_CMD(addr, cmd)  (uint32_t)((addr << 16) | cmd)
#define PROTOCOL_GET_CMD(val)  (val & 0xffff)
#define PROTOCOL_GET_ADDR(val)  ((val >> 16) & 0xff)

//STX ETX
#define PROTOCOL_STX  0X7E
#define PROTOCOL_ETX  0X7F
#define PROTOCOL_ESC  0x2D

#define PROTOCOL_DETA 0x20
#define PROTOCOL_IS_ESC(b) (b == PROTOCOL_STX || b == PROTOCOL_ETX || b == PROTOCOL_ESC)

#define PROTOCOL_FRAME_MIN_LEN  10
#define PROTOCOL_FRAME_MAX_LEN  (PROTOCOL_FRAME_MIN_LEN + PROTOCOL_DATA_MAX_LEN)
#define PROTOCOL_FRAME_BUFFER_MAX_LEN (PROTOCOL_FRAME_MAX_LEN * 2)


//STX ETX消息基类
class STXETXCommMessage : public IProtocolMessage
{
public:
    explicit STXETXCommMessage(){}
    virtual ~STXETXCommMessage(){}

public:
    uint8_t FrameType; //暂时不使用
    uint8_t FrameNo;  //内部
    
    uint8_t SrcAddr;
    uint8_t DstAddr;
    uint16_t Cmd;   
    uint8_t DataLength = 0;
    uint8_t DataBuffer[PROTOCOL_DATA_MAX_LEN];

public:
    static std::shared_ptr<STXETXCommMessage> CreateMessage(uint8_t srcAddr, uint8_t dstAddr, 
                                                            uint32_t cmd, uint8_t *data = nullptr, int dataLen = 0);
    static std::shared_ptr<STXETXCommMessage> CreateMessage(uint32_t cmd, uint8_t *data = nullptr, int dataLen = 0);
    STXETXCommMessage& InitMessage(uint32_t cmd, uint8_t *data = nullptr, int dataLen = 0);
    STXETXCommMessage& SetAddress(uint8_t srcAddr, uint8_t dstAddr);
    std::string ToString();
};

/// @brief 
/// | 7E | 帧类型(1b) | 帧号(1b) | 原地址(1b) | 目标地址(1b) | 命令(2b) | 数据长度 | 数据 | SUM CHECK | 7F |
class STXETXProtocol : public IProtocol
{
public:
    explicit STXETXProtocol();
    virtual ~STXETXProtocol();

public:
    int Packet(std::shared_ptr<IProtocolMessage> msg);
    uint8_t *GetSendBuffer();
    std::shared_ptr<IProtocolMessage> Parse(uint8_t b);
    void Reset();

    bool IsAck(std::shared_ptr<IProtocolMessage> sendMsg, std::shared_ptr<IProtocolMessage> recvMsg);
    bool IsResponse(std::shared_ptr<IProtocolMessage> sendMsg, std::shared_ptr<IProtocolMessage> recvMsg);

public:
    void SetCheckSumEnabled(bool enabled);
    bool GetCheckSumEnabled();

private:
    bool CheckSum();
    std::shared_ptr<IProtocolMessage> ParseHandle();
    void DumpErrorMessage();

private:
    uint8_t m_sendBuffer[PROTOCOL_FRAME_BUFFER_MAX_LEN]; //2*PROTOCOL_FRAME_MAX_LEN
    uint8_t m_recvBuffer[PROTOCOL_FRAME_MAX_LEN];
    
    bool m_isRecving = false;
    int m_recvLen = 0;
    int m_prevRecvByte = -1;

    bool m_checkSumEn = true;

    uint8_t m_frameNo = 0;
};

#endif // __STXEXTPROTOCOL_H__
